package com.ysq.excavator.util;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.ysq.excavator.entity.HtmlFileLink;

/**
 * 关于HTML解析的工具类
 * 
 * @author chengyu
 * 
 */
public class HtmlUtil {
	/** 日志记录 */
	static Logger logger = CommonUtil.getLogger(HtmlUtil.class);

	/**
	 * 根据url抓取网页中找到css样式,js,img链接地址及文件名
	 * 
	 * @param doc
	 *            jsoup.nodes.Document
	 * @return List<StyleSheet>
	 */
	public List<HtmlFileLink> getHtmlFileLink(Document doc,String namepostfix) {
		List<HtmlFileLink> HtmlFileLinks = new ArrayList<HtmlFileLink>();
		String postfix = "";// 文件后缀名
		int index = 0; // 用于文件名
		Elements importcss = doc.select("link[href]");// 找到document中带有link标签的元素
		for (Element link : importcss) {
			postfix = "css";
			if (link.attr("rel").equals("stylesheet")) {// 如果rel属性为HtmlFileLink
				String href = link.attr("abs:href");// 得到css样式的href的绝对路径
				// 如http://news.baidu.com/resource/css/search.css
				String filename = namepostfix + index + "." + "css";//
				HtmlFileLinks.add(new HtmlFileLink(href, filename, postfix));
				index++;
			}
		}
		Elements media = doc.select("[src]");
		for (Element link : media) {
			if (link.tagName().equals("img")) {
				String src = link.attr("abs:src");
				postfix = getPostfix(src);
				String filename = namepostfix + index + "." + postfix;
				HtmlFileLinks.add(new HtmlFileLink(src, filename, postfix));
				index++;
			}
			if (link.tagName().equals("input")) {
				if (link.attr("type").equals("Image")) {
					String src = link.attr("abs:src");
					postfix = getPostfix(src);
					String filename = namepostfix + index + "." + postfix;
					HtmlFileLinks.add(new HtmlFileLink(src, filename, postfix));
					index++;
				}
			}
			if (link.tagName().equals("javascript")
					|| link.tagName().equals("script")) {
				String src = link.attr("abs:src");
				postfix = getPostfix(src);
				String filename = namepostfix + index + "." + "js";
				HtmlFileLinks.add(new HtmlFileLink(src, filename, postfix));
				index++;
			}
			if (link.tagName().equals("iframe")) {
				String src = link.attr("abs:src");
				postfix = getPostfix(src);
				String filename = namepostfix + index + ".html";
				HtmlFileLinks.add(new HtmlFileLink(src, filename, postfix));
				index++;
			}
			if (link.tagName().equals("embed")) {
				String src = link.attr("abs:src");
				postfix = getPostfix(src);
				String filename = namepostfix + index + "." + postfix;
				HtmlFileLinks.add(new HtmlFileLink(src, filename, postfix));
				index++;
			}
		}
		return HtmlFileLinks;
	}

	/**
	 * 去掉HTML中的A标签链接地址
	 * 
	 * @param doc
	 */
	public Document removeHref(Document doc) {
		doc.select("a").removeAttr("href");// 去掉a的链接
		doc.select("img").removeAttr("onclick"); // 去掉图片onclick事件
		doc.select("input[type=submit]").attr("type", "button");// submit按钮改为普通按钮
		doc.select("input[type=button]").removeAttr("onclick"); // 去掉按钮的onclick事件
		doc.select("area").removeAttr("href");// 去掉area的链接
		doc.select("input").attr("disabled", "disabled");
		doc.select("embed").attr("wmode", "opaque");
		//doc.select("head").prepend("<META HTTP-EQUIV=expires CONTENT=\"Wed, 26 Feb 1997 08:21:57 GMT\">");
		//doc.select("head").prepend("<META HTTP-EQUIV=Cache-Control CONTENT=\"no-cache, must-revalidate\">");
		//doc.select("head").prepend("<META HTTP-EQUIV=pragma CONTENT=no-cache>");
		return doc;
	}
	/**
	 * 修改抓取网页中的css样式表链接地址,改为相对路径
	 * 
	 * @param doc
	 *            jsoup.nodes.Document
	 * @param list
	 *            List<HtmlFileLink>
	 */
	public  Document renameHref(Document doc,String namepostfix) {
		List<HtmlFileLink> list = getHtmlFileLink(doc,namepostfix);//css样式,js,img链接地址及文件名
		if (list.size() == 0) {
			return doc;
		}
		Elements imports = doc.select("link[href]");
		for (Element link : imports) {
			for (HtmlFileLink ss : list) {
				if (link.attr("abs:href").equals(ss.getHref())) {
					link.attr("href", ss.getFilename());
				}
			}
		}
		Elements media = doc.select("[src]");
		for (Element link : media) {
			for (HtmlFileLink ss : list) {
				if (link.attr("abs:src").equals(ss.getHref())) {
					link.attr("src", ss.getFilename());
				}
			}
		}
		return doc;
	}

	/**
	 * 在网页的元素中添加对象
	 * 
	 * @param doc
	 * @param tag
	 *            标签
	 * @param content
	 *            内容
	 * @return
	 */
	public  Document appendLink(Document doc, String tag, String content) {
		Element element = doc.select(tag).first();
		element.append(content);
		return doc;
	}

	/**
	 * 根据u网页中css、js、img链接地址及文件名生成本地文件
	 * 
	 * @param doc
	 * @param filepath
	 * @param timeout
	 * @throws IOException
	 */
	public  void makeHtmlLinkFile(Document doc, String filepath,
			int timeout,String ecoding,String namepostfix) {
		
		List<HtmlFileLink> list = getHtmlFileLink(doc,namepostfix);// 根据url抓取网页中找到css样式链接地址及文件名
		for (HtmlFileLink ss : list) {
			/**
			 * 生成包含iframe的html
			 */
			if (ss.getFilename().contains(".htm")||ss.getFilename().contains(".html")) {
				String nameString = StringUtils.substringBefore(ss.getFilename(), ".")+"-";
				Document document = copyURLToHtmlDoc(ss.getHref(), 60000);
				//有可能document得到空值，则排除掉这种情况
				if(document==null || doc.baseUri().equals(document.baseUri())){//遇到相同的页面不下载
					continue;
				}
				makeHtmlLinkFile(document, filepath, 60000,ecoding,nameString);// 根据u网页中css、js、img链接地址及文件名生成本地文件
				renameHref(document,nameString);// 把页面中link标签中的href属性改为本地的相对路径,正确加载css样式
				removeHref(document);
				makeHtmlByDoc("",filepath, ss.getFilename(), document, ecoding);//生成html文件
			}
			/**
			 * jsoup不支持访问js文件所以改用apache commons的fileUtil生成js和css文件
			 */
			else {
				try {
					FileUtils.copyURLToFile(new URL(ss.getHref()), new File(
							filepath + ss.getFilename()), timeout, timeout);
				} catch (MalformedURLException e) {
					logger.info("地址 :" + ss.getHref() + " 链接错误");
					continue;
				} catch (IOException e) {
					logger.info("地址 :" + ss.getHref() + " 链接超时");
					continue;
				}
			}
		}
	}

	/**
	 * 根据Url抓取页面返回document对象
	 * 
	 * @param url
	 *            链接地址
	 * @param filename
	 *            文件名称
	 * @param filepath
	 *            文件生成路径
	 * @param ecoding
	 *            编码格式
	 * @param timeout
	 *            延时
	 * @return boolean
	 */
	public  Document copyURLToHtmlDoc(String url, int timeout) {
		Document doc = null;
		try {

			doc = Jsoup.connect(url).timeout(timeout).get();// 根据Url抓取页面放入document对象
			
			doc.select("html").before("<!-- saved from url=("+new DecimalFormat("0000").format(url.length())+")"+url+" -->");
		} catch (IOException e) {
			logger.info("访问页面地址 : " + url + "链接超时");
			logger.info("访问页面地址 : " + url + "失败");
			return doc;
		} catch (IllegalArgumentException e) {
			logger.info("访问页面地址 : " + url + "输入错误");
			logger.info("访问页面地址 : " + url + "失败");
			return doc;
		}
		logger.info("访问页面地址 : " + url + "成功");
		return doc;
	}

	/**
	 * 根据url抓取网页,并生成本地的html文件 解决了css样式问题
	 * 
	 * @param url
	 *            链接地址
	 * @param filename
	 *            文件名称
	 * @param filepath
	 *            文件生成路径
	 * @param ecoding
	 *            编码格式
	 * @return boolean
	 */
	public  Document copyURLToHtmlDoc(String url, String ecoding) {
		return copyURLToHtmlDoc(url, 60000);
	}

	/**
	 * 过滤文件名,得到文件后缀
	 * 
	 * @param filename
	 *            文件名
	 * @return
	 */
	public  String getPostfix(String filename) {
		filename = StringUtils.substringAfterLast(filename, ".");
		filename = StringUtils.substringBefore(filename, "?");
		filename = StringUtils.substringBefore(filename, "/");
		filename = StringUtils.substringBefore(filename, "\\");
		filename = StringUtils.substringBefore(filename, "&");
		filename = StringUtils.substringBefore(filename, "$");
		filename = StringUtils.substringBefore(filename, "%");
		filename = StringUtils.substringBefore(filename, "#");
		filename = StringUtils.substringBefore(filename, "@");
		return filename;
	}
	/**
	 * HTML特殊字符转换
	 * @param html
	 * @return
	 */
	public  final String toHTMLChar(String html) {  
		html = html.replaceAll("\n", "\r\n");
		html = html.replaceAll("・", "&middot;");
		return html;
	}
	/**
	 * 根据抓取网页的document对象生成html文件
	 * @version 0.1 解决了window 换行符问题
	 * @param filepath
	 * @param filename
	 * @param doc
	 * @param ecoding
	 * @return
	 */
	public  boolean makeHtmlByDoc(String url,String filepath, String filename,
			Document doc, String ecoding) {
		boolean flag = false;
		try {
			String html = doc.html();
			// 中国交通网的问题
			if(!html.contains("!DOCTYPE")) {
				html = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" + html;
			}
			html = toHTMLChar(html);//HTML特殊字符转换
			FileUtils.writeStringToFile(new File(filepath + filename), html, ecoding);
			flag = true;
		} catch (IOException e) {
			logger.info("生成页面错误 文件： " + filepath + filename);
		}// 生成本地的html文件
		logger.info("生成html页面 文件 : " + filepath + filename + "完成");
		return flag;
	}

	public static void main(String[] args) {
		logger.info("begin...");
		long start = System.currentTimeMillis();
		
		String namepostfix = "chinadaily";
		
		String url = "http://news.ifeng.com/mainland/detail_2014_03/04/34415203_0.shtml";
		String filepath = "D:/sourceFile/htmlDownload/test1/";
		String filename = "index.html";// 文件名称
		String ecoding = "UTF-8";// 编码格式
		
		System.out.println(filepath);
		HtmlUtil util = new HtmlUtil();
		Document doc = util.copyURLToHtmlDoc(url, 60000);// 根据Url抓取页面放入document对象
		if (null!=doc) {
			File file = new File(filepath);
			if (file.exists()) {
				try {
					FileUtils.cleanDirectory(new File(filepath));
				} catch (IOException e) {
					logger.info("清空文件夹 :" + filepath + " 错误");
				}
			}
			util.makeHtmlLinkFile(doc, filepath, 60000,ecoding,namepostfix);// 根据u网页中css、js、img链接地址及文件名生成本地文件
			util.renameHref(doc,namepostfix);// 把页面中link标签中的href属性改为本地的相对路径,正确加载css样式
			util.removeHref(doc);// 去掉A链接
			
			String content = "<script type='text/javascript' src='../../render.js' charset='utf-8' ></script>";
			//		+ "<script type='text/javascript'>"
			//		+ "</script>";
			doc = util.appendLink(doc, "head", content);//在head标签中加载js
			util.makeHtmlByDoc("",filepath, filename, doc, ecoding);//生成html文件

			/*
			 * url = "http://www.sznews.com/";//深圳新闻
			 * url = "http://www.chinataiwan.org/";//中国台湾 
			 * url = "http://www.people.com.cn/";// 
			 * url = "http://www.xinhuanet.com/";//新华网
			 */
			logger.info("用时" + (System.currentTimeMillis() - start) / 1000 / 60 + "分钟");
		}

	}
}
